#ifndef _FENERGY_H
#define _FENERGY_H

#include <iostream>
#include <fstream>
#include <vector>
#include <string>
using namespace std;

#include "lm.h"
				 
#ifndef LM_DBL_PREC
#error Demo program assumes that levmar has been compiled with double precision, see LM_DBL_PREC!
#endif
				 
#include "PotWater.h"
#include "PotHF.h"
				 
#define MAX_DATA_SIZE 10000

/*!
*  \class PotFitter
*  \brief Class for potential fitting with LevMar algorithm
*/
class PotFitter {
	public:
		PotFitter(){};
		
		PotFitter(vector<string> &ar){
			Init(ar);
		}
		
		~PotFitter() {
			delete of;
		}	
	
		typedef  void (PotFitter::*func)(double *p, double *y, int m, int n, void *d);
		
		virtual const char* classname(){//!< identifier
			return "PotFitter";
		}
	
		void Init(vector<string> &ar);
	
		double evaluate(int debug=0){ return  evaluate(param,debug);}
			
		double evaluate(double *p,int debug=0){
			double y[MAX_DATA_SIZE];	return evaluate(p,y,debug);
		}
		
		double evaluate(double *p,double *y,int debug=0);
		
		Potential* OF_(){ return of;} //!< return pointer of objective function
		void setOF_(Potential *of_){ of=of_;} //!< assign objective function
		
		void printParam(ostream &os,double* x=NULL);//!< print full-versioned param x, if x==NULL, print current param
			
		int getNParam(){return nparam;}	//!<  return number of actual parameters
		int getNParam_inp() { return nparam_inp; }  //!<  return number of parameters (including fixed ones)
		double* getParam(){ return param;} //!< return pointer of actual parameters
		void setParam(double *x){ 
			for(int i=0;i<nparam;i++) param[i]=x[i];
		}//!< set new actual parameters 
		
		void setParam(vector<double> &x){ 
			for(int i=0;i<nparam;i++) param[i]=x[i];
		}//!< set new actual parameters
		
		
		int getNMeasure(){ return n_measure;} //!< return number of observations
		double* getMeasure(){ return measure;} //!< return pointer of observations
		
		double* getUBound(){ return ub;} //!< return pointer of upper bound
		double* getLBound(){ return lb;} //!< return pointer of lower bound
		
		void ConvertParam(double *actual,double *p);//!< convert actual parameters (get rid of fixed ones) to full-versioned param		
		
		int loadData(const char* filename,int inmode,vector<Individual> &d);
				
		/**
		 * \brief fitting model with lev-mar algorithm, see http://www.ics.forth.gr/~lourakis/levmar/
		 * \param nRuns number of iterations
		 * \param bBound whether using boundary or not (no boundary runs faster)
		 * \param debug debug level
		 * \return the number of Jacobi-iterations. structure
		 */
		int RunLevMar(int nRuns,bool bBound,int debug=0);  
			
	private:		
		
		static void levmar_func(double *p, double *y, int m, int n, void *d); //!< to link with levmar package
		
		
		void ProcessData();//!< calculate observation data
		
		
		int nparam; //!< number of actual parameters
		double param[100]; //!< actual parameters
		double ub[100],lb[100]; //!< actual bounds, all fixed parameters are removed
		vector<string> label;
		
		double measure[MAX_DATA_SIZE]; //!< consist of observation data, in that case is binding energy +rms
		double weight[MAX_DATA_SIZE]; //!< weight number 
		
		int n_measure; //!< number of data 
		

	//private: //input data
		vector<Individual> data;	
		vector<Individual> ref_inp;
		
		double param_inp[100]; //!< starting value of parameters
		double ub_inp[100],lb_inp[100]; //!< input upper and lower bounds 
		int fixed[100]; //!< determine wheter parameter are fixed
		int nfixed; //!< number of fixed parameters
		vector<string> label_inp; //!< label of parameter
		int nparam_inp; //!< number of parameters (in total)

//private:
		Potential *of;
	//VibAna vib;
};

#endif
